#include "bsp_mqtt.h"
#include "bsp_https.h"
#include "bsp_blufi.h"
#include "bsp_nvs.h"
#include <string.h>
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_log.h"
#include "mqtt_client.h"
#include "cJSON.h"
#include "bsp_param.h"
#include "esp_ota_ops.h"
#include "esp_https_ota.h"


static const char *TAG = "MQTT5";
static mqtt_rx_msg_t rx_msg;


static esp_mqtt_client_handle_t client = NULL;
static int s2d_msg_id = 0;
static int u2d_msg_id = 0;
static uint8_t mqtt_connected_flag = MQTT_DISCONNECT;
uint16_t mqtt_keepalive_count = 0;
static QueueHandle_t mqtt_rx_queue = NULL;
static QueueHandle_t mqtt_tx_queue = NULL;





static void mqtt5_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    sys_main_param_t* mqtt_callback_param = Get_sys_param_pos();
    ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32, base, event_id);
    esp_mqtt_event_handle_t event = event_data;
    int msg_id;
    ESP_LOGD(TAG, "free heap size is %" PRIu32 ", minimum %" PRIu32, esp_get_free_heap_size(), esp_get_minimum_free_heap_size());
    switch ((esp_mqtt_event_id_t)event_id) {
    case MQTT_EVENT_CONNECTED:
        ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
        msg_id = esp_mqtt_client_subscribe(client, https_get_info.s2d, 1);
        s2d_msg_id = msg_id;
        ESP_LOGI(TAG, "sent subscribe msg_id=%d", msg_id);
        msg_id = esp_mqtt_client_subscribe(client, https_get_info.u2d, 1);
        u2d_msg_id = msg_id;
        ESP_LOGI(TAG, "sent subscribe msg_id=%d", msg_id);
        ESP_LOGI(TAG, "publish msg_id=%d", msg_id);
        mqtt_connected_flag = MQTT_CONNECT;
        break;
    case MQTT_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
        mqtt_connected_flag = MQTT_DISCONNECT;
        mqtt_callback_param->ifappmqttconnect = MQTT_APP_DISCONNECT;
        break;
    case MQTT_EVENT_SUBSCRIBED:
        ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);

        break;
    case MQTT_EVENT_UNSUBSCRIBED:
        ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);

        break;
    case MQTT_EVENT_PUBLISHED:
        ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
        break;
    case MQTT_EVENT_DATA:
        ESP_LOGI(TAG, "MQTT_EVENT_DATA");
        // 接收数据：将数据推送到队列，由处理任务消费
        rx_msg.topic = event->topic;
        rx_msg.data = event->data;
        rx_msg.datalen = event->data_len;
        xQueueSend(mqtt_rx_queue, &rx_msg, portMAX_DELAY);
        break;
    case MQTT_EVENT_ERROR:
        ESP_LOGI(TAG, "MQTT_EVENT_ERROR");

        break;
    default:
        ESP_LOGI(TAG, "Other event id:%d", event->event_id);
        break;
    }
}



static void mqtt_config()
{
    char broker_uri[100] = {0};
    esp_mqtt_client_config_t mqtt5_cfg = {
        .broker.address.uri = broker_uri,             // BROKER URL
        .broker.address.port = https_get_info.port,
        .credentials.client_id = https_get_info.clientId,
        .credentials.username = https_get_info.user,
        .credentials.authentication.password = https_get_info.pwd,
        .buffer.size = 2048,
        .session.keepalive = 10,

    };

    sprintf(broker_uri,"%s%s","mqtts://",https_get_info.host);

    client = esp_mqtt_client_init(&mqtt5_cfg);
    esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt5_event_handler, NULL);
    esp_mqtt_client_start(client);

}

static void mqtt_delete()
{
    esp_mqtt_client_unregister_event(client,ESP_EVENT_ANY_ID,mqtt5_event_handler);
    esp_mqtt_client_stop(client);
}

void mqtt_req_firm_ver()
{
    nvs_info_t *mqtt_json_device_id_info = get_nvs_info();
    cJSON* cjson_send = NULL;
    char* str = NULL;
    cjson_send = cJSON_CreateObject();

    cJSON_AddStringToObject(cjson_send, "cmd", "updateFW");
    cJSON_AddStringToObject(cjson_send, "msgType", "req");
    cJSON_AddStringToObject(cjson_send, "devCode", mqtt_json_device_id_info->device_id);
    cJSON_AddStringToObject(cjson_send, "RWVer", OTA_FIRMWARE_VERSION);
    cJSON_AddStringToObject(cjson_send, "HWVer", HWVER);
    cJSON_AddStringToObject(cjson_send, "verType", VERTYPE);
    cJSON_AddNumberToObject(cjson_send, "pgType", 0);
    cJSON_AddNumberToObject(cjson_send, "relay", 0);
    str = cJSON_Print(cjson_send);
    esp_mqtt_client_publish(client, https_get_info.d2s, str, 0, 1, 0);
    cJSON_Delete(cjson_send);
    free(str);

}

void mqtt_registration_json_send()
{
    nvs_info_t *mqtt_json_device_id_info = get_nvs_info();
    cJSON* cjson_send = NULL;
    char* str = NULL;
    cjson_send = cJSON_CreateObject();
    cJSON_AddStringToObject(cjson_send, "cmd", "reg");
    cJSON_AddStringToObject(cjson_send, "msgType", "req");
    cJSON_AddStringToObject(cjson_send, "devCode", mqtt_json_device_id_info->device_id);
    cJSON_AddStringToObject(cjson_send, "RWVer", FIRMWARE_VERSION);
    cJSON_AddNumberToObject(cjson_send, "relay", 0);
    str = cJSON_Print(cjson_send);
    /* 推送签到信息 */
    esp_mqtt_client_publish(client, https_get_info.d2s, str, 0, 1, 0);
    cJSON_Delete(cjson_send);
    free(str);
}

void mqtt_ack_json_send(int msg_id_type, char* buffer)
{

    nvs_info_t *mqtt_json_device_id_info = get_nvs_info();
    cJSON* cjson_send = NULL;
    char* str = NULL;
    /* 接收 */
    cJSON* cjson_rx = NULL;
    /* 解析整段JSON数据 */
    cjson_rx = cJSON_Parse(buffer);
    cJSON* cjson_rec_messageid = cJSON_GetObjectItem(cjson_rx, "messageId");

    /* 创建一个JSON数据对象(链表头结点) */
    cjson_send = cJSON_CreateObject();
    /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
    cJSON_AddStringToObject(cjson_send, "cmd", "u2dRealData");
    cJSON_AddStringToObject(cjson_send, "msgType", "ack");
    if(cjson_rec_messageid != 0){
        cJSON_AddStringToObject(cjson_send, "messageId", cjson_rec_messageid->valuestring);
    }
    cJSON_AddStringToObject(cjson_send, "deviceCode", mqtt_json_device_id_info->device_id);
    cJSON_AddStringToObject(cjson_send, "reason", "NULL");
    cJSON_AddStringToObject(cjson_send, "result", "success");
    str = cJSON_Print(cjson_send);
    /* 推送信息 */
    if(msg_id_type == s2d_msg_id){
        esp_mqtt_client_publish(client, https_get_info.d2s, str, 0, 0, 0);
    }else if(msg_id_type == u2d_msg_id){
        esp_mqtt_client_publish(client, https_get_info.d2u, str, 0, 0, 0);
    }
    cJSON_Delete(cjson_send);
    cJSON_Delete(cjson_rx);
    free(str);

}


void mqtt_report_json_d2u_send(void *send_data)
{

    nvs_info_t *mqtt_json_device_id_info = get_nvs_info();
    send_param_t *a = send_data;
    cJSON* cjson_send = NULL;
    char* str = NULL;

    cjson_send = cJSON_CreateObject();
    /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
    cJSON_AddStringToObject(cjson_send, "cmd", "d2uRealData");
    cJSON_AddStringToObject(cjson_send, "msgType", "req");
    cJSON_AddStringToObject(cjson_send, "deviceCode", mqtt_json_device_id_info->device_id);
    cJSON_AddStringToObject(cjson_send, "op", "uStatus");

    cJSON_AddNumberToObject(cjson_send, "A", a->send_strength);
    cJSON_AddNumberToObject(cjson_send, "mode", a->send_mode);
    cJSON_AddNumberToObject(cjson_send, "countdown", a->send_countdown);
    cJSON_AddNumberToObject(cjson_send, "durationSeting", a->send_runtime);
    cJSON_AddNumberToObject(cjson_send, "status", a->send_status);
    cJSON_AddNumberToObject(cjson_send, "fault", a->send_error_type);

    str = cJSON_Print(cjson_send);
    esp_mqtt_client_publish(client, https_get_info.d2u, str, 0, 1, 0);
    cJSON_Delete(cjson_send);
    free(str);
}

void mqtt_report_json_ota_send(uint8_t ota_status)
{

    nvs_info_t *mqtt_json_device_id_info = get_nvs_info();
    cJSON* cjson_send = NULL;
    char* str = NULL;

    cjson_send = cJSON_CreateObject();
    /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
    cJSON_AddStringToObject(cjson_send, "cmd", "d2uRealData");
    cJSON_AddStringToObject(cjson_send, "msgType", "req");
    cJSON_AddStringToObject(cjson_send, "deviceCode", mqtt_json_device_id_info->device_id);
    cJSON_AddStringToObject(cjson_send, "op", "uFw");
    cJSON_AddStringToObject(cjson_send, "ver", OTA_FIRMWARE_VERSION);
    cJSON_AddStringToObject(cjson_send, "verType", VERTYPE);
    cJSON_AddNumberToObject(cjson_send, "pgType", 0);
    cJSON_AddNumberToObject(cjson_send, "type", ota_status);
    if(ota_status == OTA_SUCCESS){
        cJSON_AddNumberToObject(cjson_send, "progress", 100);
    }else{
        cJSON_AddNumberToObject(cjson_send, "progress", 50);
    }
    
    str = cJSON_Print(cjson_send);
    esp_mqtt_client_publish(client, https_get_info.d2u, str, 0, 1, 0);
    cJSON_Delete(cjson_send);
    free(str);
}


// 发送函数（线程安全）
void mqtt_send(uint8_t send_type, void *data) 
{
    mqtt_tx_msg_t mqtt_send_msg;
    mqtt_send_msg.send_type = send_type;
    mqtt_send_msg.data = data;
    xQueueSend(mqtt_tx_queue, &mqtt_send_msg, portMAX_DELAY);
}

void mqtt_parse_rx_s2d_data(char *buffer)
{
    cJSON* cjson_rx = NULL;
    /* 解析整段JSON数据 */
    cjson_rx = cJSON_Parse(buffer);
    if(cjson_rx == NULL){
        cJSON_Delete(cjson_rx);
        return;
    }
    cJSON* cjson_rec_cmd = cJSON_GetObjectItem(cjson_rx, "cmd");
    cJSON* cjson_rec_url = cJSON_GetObjectItem(cjson_rx, "url");
    cJSON* cjson_rec_force = cJSON_GetObjectItem(cjson_rx, "force");

    if(strcmp(cjson_rec_cmd->valuestring,"updateFW") == 0){

        if(cjson_rec_url != 0){
            memset(ota_firm_ver_url,0,sizeof(ota_firm_ver_url));
            memcpy(ota_firm_ver_url, cjson_rec_url->valuestring, strlen(cjson_rec_url->valuestring));
        }

    }

    /* 清除cjson申请的内存 */
    cJSON_Delete(cjson_rx);
}

void mqtt_parse_rx_u2d_data(char *buffer)
{
    sys_main_param_t* mqtt_rx_param = Get_sys_param_pos();
    cJSON* cjson_rx = NULL;
    /* 解析整段JSON数据 */
    cjson_rx = cJSON_Parse(buffer);
    if(cjson_rx == NULL){
        cJSON_Delete(cjson_rx);
        return;
    }
    cJSON* cjson_rec_op = cJSON_GetObjectItem(cjson_rx, "op");
    cJSON* cjson_rec_A = cJSON_GetObjectItem(cjson_rx, "A");
    cJSON* cjson_rec_mode = cJSON_GetObjectItem(cjson_rx, "mode");


    if(cjson_rec_op != 0){
        if(strcmp(cjson_rec_op->valuestring,"RDStart") == 0){
            mqtt_keepalive_count = 0;
            mqtt_rx_param->ifappmqttconnect = MQTT_CONNECT_PRIORITY_H;
        }else if(strcmp(cjson_rec_op->valuestring,"RDKeepalive") == 0){
            mqtt_keepalive_count = 0;
            mqtt_rx_param->ifappmqttconnect = MQTT_APP_CONNECT;
        }else if(strcmp(cjson_rec_op->valuestring,"RDStop") == 0){
            mqtt_rx_param->ifappmqttconnect = MQTT_APP_DISCONNECT;
        }else if(strcmp(cjson_rec_op->valuestring,"time") == 0){
            if(mqtt_rx_param->sys_status == SYS_PAUSE){
                mqtt_rx_param->sys_status = SYS_STOP;
            }else if(mqtt_rx_param->sys_status == SYS_STOP){
                if((++mqtt_rx_param->sys_runtime) > RUN_60MIN){
                    mqtt_rx_param->sys_runtime = RUN_5MIN;
                }
            }
        }else if(strcmp(cjson_rec_op->valuestring,"STT") == 0){
            if(mqtt_rx_param->sys_status == SYS_RUN_NORMAL){
                mqtt_rx_param->sys_status = SYS_PAUSE;
            }else{
                mqtt_rx_param->sys_status = SYS_RUN_NORMAL;
            }

        }else if(strcmp(cjson_rec_op->valuestring,"updateFw") == 0){
            /* OTA请求 */
            if(ota_req_flag == OTA_IDLE){
                ota_req_flag = OTA_REC_REQ;
            }
            
        }
        if(mqtt_rx_param->sys_status != SYS_RUN_NORMAL){
            if((cjson_rec_mode != 0) && (cjson_rec_mode->valueint < MODE_MAX)){
                mqtt_rx_param->sys_mode = cjson_rec_mode->valueint;
            }
    
            if((cjson_rec_A != 0) && (cjson_rec_A->valueint <= POWER_8)){
                if(mqtt_rx_param->sys_mode == MODE_DC){
                    mqtt_rx_param->sys_power = (cjson_rec_A->valueint > POWER_2)?POWER_2:cjson_rec_A->valueint;
                }else{
                    mqtt_rx_param->sys_power = cjson_rec_A->valueint;
                }
                
            }

        }


        
    }
    /* 清除cjson申请的内存 */
    cJSON_Delete(cjson_rx);

}

static void ota_begin_config()
{
    ESP_LOGI(TAG, "Starting OTA upgrade...");
    
    esp_http_client_config_t config = {
        .url = ota_firm_ver_url,
        .transport_type = HTTP_TRANSPORT_OVER_TCP,
        .skip_cert_common_name_check = true,

    };
    esp_https_ota_config_t ota_config = {
        .http_config = &config,
    };
    /* 开始ota */
    mqtt_send(MQTT_SEND_D2U_OTA, NULL);
    esp_err_t ret = esp_https_ota(&ota_config);
    
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "OTA Successful, Rebooting...");
        ota_req_flag = OTA_SUCCESS;

    } else {
        ESP_LOGE(TAG, "OTA Failed!");
        ota_req_flag = OTA_FAIL;

    }
}

/* OTA升级任务 */
void http_ota_task(void *pvParameter)
{
    while (1) {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        if(ota_req_flag == OTA_START){
            mqtt_send(MQTT_SEND_D2U_OTA, NULL);
        }else if(ota_req_flag == OTA_SUCCESS){
            mqtt_send(MQTT_SEND_D2U_OTA, NULL);
            vTaskDelay(2000/portTICK_PERIOD_MS);
            esp_restart();
        }else if(ota_req_flag == OTA_FAIL){
            mqtt_send(MQTT_SEND_D2U_OTA, NULL);
            vTaskDelay(2000/portTICK_PERIOD_MS);
            esp_restart();
        }
    }
}
extern void example_wifi_connect();
void mqtt_task(void *pvParameters)
{
    mqtt_config();
    for(;;){
        if(gl_sta_got_ip == true){
            /* 是否开启ota */
            if(ota_req_flag == OTA_REC_REQ){
                ota_req_flag = OTA_START;
                xTaskCreate(&http_ota_task, "http_ota_task", 8192, NULL, 11, NULL);
                ota_begin_config();
            }

        }else{
            vTaskDelay(5000/portTICK_PERIOD_MS);
            example_wifi_connect();
        }
        vTaskDelay(1000/portTICK_PERIOD_MS);
    }
}



// 发送数据处理任务
static void mqtt_tx_task(void *pvParameters) {
    sys_main_param_t* mqtt_send_param = Get_sys_param_pos();
    mqtt_tx_msg_t mqtt_tx_msg = {0};
    for(;;){
        if (xQueueReceive(mqtt_tx_queue, &mqtt_tx_msg, portMAX_DELAY)) {
    
            switch(mqtt_tx_msg.send_type){
                case MQTT_SEND_D2S_QD:
                    ESP_LOGI(TAG, "SEND_D2S_QD");
                    mqtt_registration_json_send();
                    break;
                case MQTT_SEND_D2S_GJ:
                    ESP_LOGI(TAG, "SEND_D2S_GJ");
                    mqtt_req_firm_ver();
                    break;
                case MQTT_SEND_D2S_ACK:
                    ESP_LOGI(TAG, "SEND_D2S_ACK");
                    mqtt_ack_json_send(s2d_msg_id, mqtt_tx_msg.data);
                    break;
                case MQTT_SEND_D2U_ZT:
                    
                    if(mqtt_send_param->ifappmqttconnect >= MQTT_APP_CONNECT){
                        mqtt_report_json_d2u_send(mqtt_tx_msg.data);
                        ESP_LOGI(TAG, "SEND_D2U_ZT");
                    }
                    
                    break;
                case MQTT_SEND_D2U_ACK:
                    
                    if(mqtt_send_param->ifappmqttconnect >= MQTT_APP_CONNECT){
                        mqtt_ack_json_send(u2d_msg_id, mqtt_tx_msg.data);
                        ESP_LOGI(TAG, "SEND_D2U_ACK");
                    }
                    
                    break;
                case MQTT_SEND_D2U_OTA:
                    
                    if(mqtt_send_param->ifappmqttconnect >= MQTT_APP_CONNECT){
                        mqtt_report_json_ota_send(ota_req_flag);
                        ESP_LOGI(TAG, "SEND_D2U_OTA");
                    }
                    
                    break;
                default:
                    break;

            }

        }
    }
}
// 接收数据处理任务
static void mqtt_rx_task(void *pvParameters) {
    mqtt_rx_msg_t mqtt_rx_msg = {0};
    for(;;){
        if (xQueueReceive(mqtt_rx_queue, &mqtt_rx_msg, portMAX_DELAY)) {
            if(strstr(mqtt_rx_msg.topic, https_get_info.u2d) != NULL){
                ESP_LOGI(TAG, "REC_U2D_NOW");
                mqtt_parse_rx_u2d_data(mqtt_rx_msg.data);
                mqtt_send(MQTT_SEND_D2U_ACK, mqtt_rx_msg.data);
            }else if(strstr(mqtt_rx_msg.topic, https_get_info.s2d) != NULL){
                ESP_LOGI(TAG, "REC_S2D_NOW");
                mqtt_parse_rx_s2d_data(mqtt_rx_msg.data);
                mqtt_send(MQTT_SEND_D2S_ACK, mqtt_rx_msg.data);
            }
        }
    }
}



void mqtt_init()
{

    mqtt_rx_queue = xQueueCreate(20, sizeof(mqtt_rx_msg_t));
    mqtt_tx_queue = xQueueCreate(20, sizeof(mqtt_tx_msg_t));

    xTaskCreate(mqtt_rx_task, "mqtt_rx_task", 4096, NULL, 12, NULL);
    xTaskCreate(mqtt_tx_task, "mqtt_tx_task", 4096, NULL, 12, NULL);
}













